<!--
该控件用于模拟excel的输入控件，可以识别公式、单元格引用等。
-->
<template>
  <div
    class="input-div"
    contenteditable="true"
    ref="inputDiv"
    v-html="innerHtml"
    @input="inputChange"
    @keydown="keyDown"
  ></div>
</template>

<script>
const CELL_REF_REG = /^([A-Za-z]+[1-9]\d*)$/g;
import { EXCEL_FUNCTIONS } from "./exceldata";
export default {
  props: {
    value: {
      type: String,
    },
  },
  data() {
    return {
      // innerHtml:""
      startOffset: null,
      childIndex: null,
      refCells: [],
      highlightColors: ["#C472c4", "#ed7d31", "#ffc000", "#5b9bd5", "#70ad47"],
    };
  },
  computed: {
    innerHtml() {
      return this.highlightCells(this.value);
    },
  },
  watch: {
    value(nval) {
      this.$nextTick(() => {
        const selection = window.getSelection();

        selection.removeAllRanges(); // 清除当前选区
        const range = document.createRange(); // 创建一个新的范围对象
        const start = !this.startOffset ? 0 : this.startOffset;
        if (start === 0) {
          range.setStart(this.$refs.inputDiv, 0);
          selection.addRange(range);
          this.$refs.inputDiv.focus();
          return;
        }
        let pointer = 0;
        let curNode = null;
        for (let i in this.$refs.inputDiv.childNodes) {
          let node = this.$refs.inputDiv.childNodes[i];
          let text = node.textContent || node.innerText || "";
          if (start - pointer > text.length) {
            pointer = pointer + text.length;
            continue;
          } else {
            pointer = start - pointer;
            curNode = node;
            break;
          }
        }
        const baseNode =
          curNode.tagName === "SPAN" ? curNode.firstChild : curNode;
        range.setStart(baseNode, pointer);
        selection.addRange(range); // 添加新的选区
        this.$refs.inputDiv.focus();
      });
    },
    refCells: {
      handler(nval, oval) {
        if (
          nval.length === oval.length &&
          nval.every((val, i) => val === oval[i])
        ) {
          return;
        }
        this.$emit("refcellchanged", nval);
      },
      deep: true,
    },
  },
  mounted() {
    this.$refs.inputDiv.addEventListener(
      "compositionend",
      this.inputCompositionEnd
    );
    this.initValue = this.value;
  },
  unmounted() {
    this.$refs.inputDiv.removeEventListener(
      "compositionend",
      this.inputCompositionEnd
    );
  },
  methods: {
    keyDown(event) {
      if (event.code === "KeyZ" && event.ctrlKey === true) {
        this.startOffset = this.initValue.length;
        this.$emit("input", this.initValue);
      }
    },
    inputCompositionEnd(e) {
      console.log();
      this.inputChange(e, true);
    },
    inputChange(event, inputend = false) {
      if (!inputend && event.isComposing) {
        return;
      }
      const selection = window.getSelection();
      let curEditNode = selection.baseNode;
      const range = selection.getRangeAt(0);
      const offset = range.startOffset;

      if (curEditNode.parentNode.tagName === "SPAN") {
        curEditNode = curEditNode.parentNode;
      }
      let pointer = 0;
      for (let i in curEditNode.parentNode.childNodes) {
        let node = curEditNode.parentNode.childNodes[i];
        if (node === curEditNode) {
          pointer += offset;
          break;
        } else {
          pointer += (node.textContent || node.innerText || "").length;
        }
      }
      this.startOffset = pointer;
      console.log("this.startOffset", this.startOffset);
      this.$emit("input", this.$refs.inputDiv.innerText);
    },
    highlightCells(text) {
      if (text.length === 0 || text[0] != "=") {
        return text;
      }
      // 将文本按单词分割，并重建 HTML
      const parts = text.split(/(\w+)/);

      let html = "";
      let refCell = [];
      for (let i = 0; i < parts.length; i++) {
        const part = parts[i];
        if (CELL_REF_REG.test(part)) {
          refCell.push(part);
          html += `<span class="cell-ref" style='${this.getCellRefStyle(
            i
          )}'>${part}</span>`;
        } else if (
          EXCEL_FUNCTIONS.has(part.toUpperCase()) &&
          parts.length > i + 1 &&
          parts[i + 1].trim() === "("
        ) {
          html += `<span class="func-ref" '>${part}</span>`;
        } else {
          // 转义 HTML 特殊字符防止 XSS
          html += this.escapeHtml(part);
        }
      }
      this.refCells = refCell;
      return html;
    },
    escapeHtml(str) {
      return str.replace(
        /[&<>"']/g,
        (match) =>
          ({
            "&": "&amp;",
            "<": "&lt;",
            ">": "&gt;",
            '"': "&quot;",
            "'": "&#x27;",
          }[match])
      );
    },
    getCellRefStyle(i) {
      const index = i % this.highlightColors.length;
      return "background:" + this.highlightColors[index];
    },
  },
};
</script>

<style>
.cell-ref {
  padding: 1px;
  border-radius: 4px;
}
.func-ref {
  color: #1e96f2;
}
.input-div:focus {
  outline: 1px solid var(--theme-primary-color, #1e96f2);
}
</style>
